﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using Fabrication.DataStructures;
using Fabrication.Extensions;
using Fabrication.ValueProviders;

namespace Fabrication
{
    public static class NumericRuleExtensions
    {
        public static IBuilderOptions<T> UseRange<T>(this PropertySelector<T, int> propertySelector, int minimum, int maximum)
        {
            var provider = new FunctionValueProvider<T, int>(x => RandomNumberGenerator.GetInteger(minimum, maximum));
            return propertySelector.Use(provider);
        }

        public static IBuilderOptions<T> UseRange<T>(this PropertySelector<T, long> propertySelector, long minimum, long maximum)
        {
            var provider = new FunctionValueProvider<T, long>(x => RandomNumberGenerator.GetLong(minimum, maximum));
            return propertySelector.Use(provider);
        }

        public static IBuilderOptions<T> UseRange<T>(this PropertySelector<T, float> propertySelector, float minimum, float maximum)
        {
            var provider = new FunctionValueProvider<T, float>(x => RandomNumberGenerator.GetFloat(minimum, maximum));
            return propertySelector.Use(provider);
        }

        public static IBuilderOptions<T> UseRange<T>(this PropertySelector<T, double> propertySelector, double minimum, double maximum)
        {
            var provider = new FunctionValueProvider<T, double>(x => RandomNumberGenerator.GetDouble(minimum, maximum));
            return propertySelector.Use(provider);
        }

        public static IBuilderOptions<T> UseRange<T>(this PropertySelector<T, decimal> propertySelector, decimal minimum, decimal maximum)
        {
            var provider = new FunctionValueProvider<T, decimal>(x => RandomNumberGenerator.GetDecimal(minimum, maximum));
            return propertySelector.Use(provider);
        }

        public static IBuilderOptions<T> UseSequence<T>(this PropertySelector<T, int> propertySelector, int beginAt, int endAt)
        {
            var items = new List<int>();
            if (beginAt < endAt)
                for (int i = beginAt; i <= endAt; i++)
                    items.Add(i);
            else
                for (int i = beginAt; i >= endAt; i--)
                    items.Add(i);

            var sequence = new Sequence<int>(items);
            return propertySelector.Use(x => sequence.Next());
        }

        public static IBuilderOptions<T> UseSequence<T>(this PropertySelector<T, long> propertySelector, long beginAt, long endAt)
        {
            var items = new List<long>();
            if (beginAt < endAt)
                for (long i = beginAt; i <= endAt; i++)
                    items.Add(i);
            else
                for (long i = beginAt; i >= endAt; i--)
                    items.Add(i);

            var sequence = new Sequence<long>(items);
            return propertySelector.Use(x => sequence.Next());
        }

        public static IBuilderOptions<T> GeneratePostCode<T>(this PropertySelector<T, int> propertySelector)
        {
            return propertySelector.Use(new PostCodeProvider());
        }

        public static IBuilderOptions<T> IsGreaterThan<T>(this EnsurePropertySelector<T, int> targetPropertySelector, Expression<Func<T, int>> member)
        {
            var sourcePropertyName = member.GetPropertyName();
            var builderOptions = targetPropertySelector.BuilderOptions;
            builderOptions.AddEnsureRule<int, int>(typeof(T), sourcePropertyName, targetPropertySelector.PropertyName, x => x + RandomNumberGenerator.GetInteger(1, 30));
            return builderOptions;
        }

        public static IBuilderOptions<T> IsLessThan<T>(this EnsurePropertySelector<T, int> targetPropertySelector, Expression<Func<T, int>> member)
        {
            var sourcePropertyName = member.GetPropertyName();
            var builderOptions = targetPropertySelector.BuilderOptions;
            builderOptions.AddEnsureRule<int, int>(typeof(T), sourcePropertyName, targetPropertySelector.PropertyName, x => x + RandomNumberGenerator.GetInteger(1, 30) * -1);
            return builderOptions;
        }
    }
}